#include "lab3_problem3.h"

#include <iostream>
#include "../p1/IterationMethods.h"

namespace Lab3
{
    namespace Problem3
    {
        void problem3()
        {
        
            std::cout << "Lab 3 - Problem 3:" << std::endl;
        
        	static const double errorTolerance1 = 0.00000000001;
        	static const double errorTolerance2 = 0.0001;
        	static const uint32_t maxIterations = 1000000;

        	// Define the path of the files that contains the matrices
        	// A1, b1 and x0
        	static const std::string filePathForA1 = "lab3/p3/datos/A1.txt";
        	static const std::string filePathForb1 = "lab3/p3/datos/b1.txt";
        	static const std::string filePathForx0 = "lab3/p3/datos/initialX.txt";

        	// Resolve A1 * x = b1 using Jacobi and Gauss-Seidel methods.
        	uint32_t lastIteration = 0;
        	double firstOrderNorm = 0.0;
        	static const uint32_t jacobiMatrixDimension1 = 3;
        	Utils::Matriz jacobiMatrix1(jacobiMatrixDimension1, 1);

        	NumericalAnalysis::IterationMethod(NumericalAnalysis::Method_Jacobi, jacobiMatrixDimension1, filePathForA1, 
        	                                   filePathForb1, filePathForx0, errorTolerance1,
        		                               maxIterations, lastIteration, firstOrderNorm, jacobiMatrix1);

        	// Print last iteration.
        	std::cout << "Jacobi method - problem a - last iteration = " << lastIteration << std::endl;

        	Utils::PrintMatrix(jacobiMatrix1);

        	static const uint32_t gaussSeidelMatrixDimension1 = 3;
        	Utils::Matriz gaussSeidelMatrix1(gaussSeidelMatrixDimension1, 1);
        	NumericalAnalysis::IterationMethod(NumericalAnalysis::Method_GaussSeidel, gaussSeidelMatrixDimension1, 
        	                                   filePathForA1, filePathForb1, filePathForx0, errorTolerance1,
        		                               maxIterations, lastIteration, firstOrderNorm, gaussSeidelMatrix1);

        	// Print last iteration.
        	std::cout << "Gauss-Seidel method - problem a - last iteration = " << lastIteration << std::endl;

        	Utils::PrintMatrix(gaussSeidelMatrix1);

        	// Define the path of the files that contains the matrices
        	// A2 and b2.
        	static const std::string filePathForA2 = "lab3/p3/datos/A2.txt";
        	static const std::string filePathForb2 = "lab3/p3/datos/b2.txt";

        	// Resolve A2 * x = b2 using Gauss-Seidel methods.
        	static const uint32_t gaussSeidelMatrixDimension2 = 4;
        	Utils::Matriz gaussSeidelMatrix2(gaussSeidelMatrixDimension2, 1);
        	NumericalAnalysis::IterationMethod(NumericalAnalysis::Method_GaussSeidel, gaussSeidelMatrixDimension2, 
        	                                   filePathForA2, filePathForb2, filePathForx0, errorTolerance2,
        		                               maxIterations, lastIteration, firstOrderNorm, gaussSeidelMatrix2);

        	// Print last iteration.
        	std::cout << "Gauss Seidel method - problem b - last iteration = " << lastIteration << std::endl;

        	Utils::PrintMatrix(gaussSeidelMatrix2);

        	static const uint32_t jacobiMatrixDimension2 = 3;
        	Utils::Matriz jacobiMatrix2(jacobiMatrixDimension2, 1);
        	NumericalAnalysis::IterationMethod(NumericalAnalysis::Method_Jacobi, jacobiMatrixDimension2, filePathForA2, 
        	                                   filePathForb2, filePathForx0, errorTolerance2,
        		                               maxIterations, lastIteration, firstOrderNorm, jacobiMatrix2);

        	std:: cout << "Jacobi method - problem b - last iteration = " << lastIteration << std::endl;

        	Utils::PrintMatrix(jacobiMatrix2);
        	
        	//
        	// Conclusions
        	// Problem b cannot be solved using Jacobi method!!!!
        	//
        }       
    }
}
